home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / yase.arc / PRINTF.ASM < prev    next >
Assembly Source File  |  1986-12-13  |  10KB  |  281 lines

  1. ******************************************************************
  2. * COPYRIGHT (C) 1986 by Donald Krantz and James Stanley
  3. * - Note: This is a real, live, actual, registered copyright,
  4. *   and should be treated as such. This source code is from
  5. *   the book "68000 Assembly Language", Krantz and Stanley,
  6. *   Addison-Wesley Publishing Company, Reading, MA, 1986.
  7. *   Permission granted by the authors for non-commercial use
  8. *   in programs released to the public domain, as long as this
  9. *   copyright notice remains attached and visible.
  10. *
  11. *****************************************************************
  12. * PRINTF - subset/superset of C printf standard I/O function
  13. * Control args:
  14. *
  15. *    push last parameter in control string first, then next-to
  16. *    last, etc.  Push address of control string last.
  17. *
  18. *     %d: print signed decimal word
  19. *     %u: print unsigned decimal word
  20. *     %D: print signed decimal longword
  21. *     %U: print unsigned decimal longword
  22. *     %x: print hexadecimal word
  23. *     %X: print hexadecimal longword
  24. *     %s: print null terminated string
  25. *     %c: print character
  26. *     %v: cursor (x,y) - push Y, then X, as words.
  27. *    %default: print next character as literal
  28. *****************************************************************
  29.     xdef    printf
  30.     xref    case,putc,cursor
  31. *****************************************************************
  32. * Local variable displacement definitions
  33. leftj    equ    -2        * left justify displacement
  34. field    equ    -4        * field width displacement
  35. signf    equ    -6        * sign flag
  36. *****************************************************************
  37. printf:
  38.     link    a6,#-6        * make 2 (word) local vars
  39.     movem.l    d0-d6/a0-a2,-(a7)
  40.     move.l    8(a6),a1    * get control string address
  41.     lea    12(a6),a2    * get pointer to parameters
  42. loop:
  43.     move.b    (a1)+,d0    * get control string character
  44.     beq    exit        * quit if it's a null.
  45.     ext.w    d0        * clear high byte
  46.     cmp.b    #'%',d0        * see if it's control flag
  47.     bne    no_ctl        * branch if not
  48.     clr.w    leftj(a6)    * clear left justify flag
  49.     clr.w    field(a6)    * clear field width
  50.     clr.w    signf(a6)    * clear sign flag
  51. lp0pf:
  52.     move.b    (a1)+,d0    * get control string character
  53.     ext.w    d0        * clear high byte 
  54.     cmp.b    #'-',d0        * is it minus?
  55.     bne    sk0pf        * no, keep going
  56.     move.w    #1,leftj(a6)     * set left justify flag
  57.     bra    lp0pf        * try for next char
  58. sk0pf:
  59.     cmp.b    #'0',d0        * is it smaller than a digit?
  60.     blt    sk1pf        * yes, continue processing
  61.     cmp.b    #'9',d0        * is it larger than a digit?
  62.     bgt    sk1pf        * yes, continue processing
  63.     move.w    field(a6),d1    * get current field size
  64.     mulu    #10,d1        * shift left one decimal digit
  65.     and.w    #$000F,d0    * make ASCII digit binary
  66.     add.w    d0,d1        * add current digit
  67.     move.w    d1,field(a6)    * store answer
  68.     bra    lp0pf        * get next format char        
  69. sk1pf:
  70.     move.l    #dispatch,a0    * get case table address for case
  71.     bra    case        * go do case select.
  72. no_ctl:
  73.     move.w    d0,-(a7)    * push character
  74.     bsr    putc        * print it
  75.     addq.l    #2,a7        * trash parameter
  76.     bra    loop        * do it again.
  77. exit:
  78.     movem.l    (a7)+,d0-d6/a0-a2
  79.     unlk    a6
  80.     rts
  81. *****************************************************************
  82. d_arg:
  83.     move.w    (a2)+,d0    * get value, move pointer
  84.     ext.l    d0        * convert to common format
  85.     bsr    sign        * print sign, if any, take abs()
  86.     bra    printdec    * go print value
  87. *****************************************************************
  88. u_arg:    
  89.     move.w    (a2)+,d0    * get value, move pointer
  90.     and.l    #$0000FFFF,d0    * zero out high word
  91.     bra    printdec    * go print value
  92. *****************************************************************
  93. D_arg:
  94.     move.l    (a2)+,d0    * get value, move pointer
  95.     bsr    sign        * print sign, if any, take abs()
  96.     bra    printdec    * go print value
  97. *****************************************************************
  98. U_arg:
  99.     move.l    (a2)+,d0    * get value, move pointer
  100.     bra    printdec    * print decimal value
  101. *****************************************************************
  102. * SIGN - print sign if needed and takes abs() of value
  103. sign:
  104.     tst.l    d0        * is it negative?
  105.     bpl    sk0_sg        * exit if not
  106.     move.w    #-1,signf(a6)    * flag sign needed
  107.     subq.w    #1,field(a6)    * take away one for sign
  108.     neg.l    d0        * change the sign
  109. sk0_sg:
  110.     rts
  111. *****************************************************************
  112. * printdec - common decimal output routine. Value in D0. 
  113. printdec:
  114.     clr.w    d1        * output digit count
  115. lp0_pd:
  116.     divu    #10,d0        * divide number by 10
  117.     bvs    o_flow        * number too large
  118.     swap    d0        * get remainder in d0.w
  119.     move.w    d0,-(a7)    * push digit
  120.     addq.w    #1,d1        * bump digit count
  121.     clr.w    d0        * get rid of remainder
  122.     swap    d0        * put quotient into d0.w
  123.     tst.w    d0        * zero means we're done
  124.     bne    lp0_pd        * jumps if not done.
  125.     move.w    d1,d6        * used for field adjust
  126.     bsr    prefix        * do prefix spaces
  127.     subq.w    #1,d1        * adjust loop index counter
  128. lp2_pd:
  129.     add.w    #$30,(a7)    * make digit TOS into ASCII
  130.     bsr    putc        * output digit
  131.     addq.l    #2,a7        * eat digit from TOS
  132.     dbra    d1,lp2_pd    * output all digits
  133.     bsr    postfix        * do postfix spaces
  134.     bra    loop        * exit to control parser
  135. o_flow:
  136.     move.l    #oflowstr,-(a7)    * push control string address
  137.     bsr    printf        * print it
  138.     addq.l    #4,a7        * adjust stack
  139.     bra    loop        * continue
  140. oflowstr:
  141.     dc.w    '*overflow*',0
  142. *****************************************************************
  143. * PREFIX - outputs prefix spaces and/or sign
  144. prefix:
  145.     tst.w    field(a6)    * check if field nonzero
  146.     ble    chksign        * if zero, just boogie on out
  147.     tst.w    leftj(a6)    * left justify selected?
  148.     bne    chksign        * jump if no
  149.     sub.w    d6,field(a6)    * digits allowed - digits actual
  150.     ble    chksign        * exit if no spaces needed
  151. lp0_pr:
  152.     move.w    d0,-(a7)    * save d0 across call to _put
  153.     move.w    #'  ',-(a7)    * space to output
  154.     bsr    putc        * output the space
  155.     addq.l    #2,a7        * adjust stack
  156.     move.w    (a7)+,d0    * retrieve d0
  157.     subq.w    #1,field(a6)    * decrement loop index
  158.     bne    lp0_pr        * do again if more spaces needed
  159. chksign:
  160.     tst.w    signf(a6)    * sign needed?
  161.     beq    chkexit        * jump if no
  162.     move.l    d0,d2        * save d0 across call to _put
  163.     move.w    #' -',-(a7)    * push sign
  164.     bsr    putc        * output it
  165.     addq.l    #2,a7        * adjust stack
  166.     move.l    d2,d0        * retrieve argument
  167. chkexit:
  168.     rts
  169. *****************************************************************
  170. * POSTFIX - prints postfix spaces in field
  171. postfix:
  172.     sub.w    d6,field(a6)    * digits allowed - digits actual
  173.     ble    sk1_po        * exit if no spaces needed
  174. lp0_po:
  175.     move.w    #'  ',-(a7)    * space to output
  176.     bsr    putc        * output the space
  177.     addq.l    #2,a7        * adjust stack
  178.     subq.w    #1,field(a6)    * decrement loop index
  179.     bne    lp0_po        * do again if more spaces needed
  180. sk1_po:
  181.     rts
  182. *****************************************************************
  183. x_arg:
  184.     move.w    #3,d1        * number of digits to print
  185.     move.w    #4,d6        * used for field adjust
  186.     move.w    (a2)+,d2    * transfer output value
  187.     swap    d2        * position output value
  188.     bra    printhex    * go print it
  189. *****************************************************************
  190. X_arg:
  191.     move.w    #7,d1        * number of digits to print
  192.     move.w    #8,d6        * used for field adjust
  193.     move.l    (a2)+,d2    * transfer output value
  194.     bra    printhex    * go print it
  195. *****************************************************************
  196. * PRINTHEX - outputs value held in D2 in hex. D1 is digit count
  197. printhex:
  198.     bsr    prefix        * output prefix spaces
  199. lp0ph:
  200.     move.l    #hexdigits,a0    * address of translate table
  201.     rol.l    #4,d2        * put MSD in low four bits
  202.     move.w    d2,d0        * we're only interested in LSD
  203.     and.w    #$000F,d0    * so we hack off all but LSD
  204.     move.b    0(a0,d0.w),d0    * get digit
  205.     move.w    d0,-(a7)    * push for output
  206.     bsr    putc        * output it
  207.     addq.l    #2,a7        * trash parameter
  208.     dbra    d1,lp0ph    * loop for next digit
  209.     bsr    postfix        * do postfix spaces
  210.     bra    loop        * return to control string parser
  211. hexdigits:
  212.     dc.w    '0123456789ABCDEF'
  213. *****************************************************************
  214. s_arg:
  215.     move.l    (a2),a0        * get string address from stack
  216.     clr.w    d6        * get strlen for field adjust
  217. slen:
  218.     tst.b    (a0)+        * look for terminal null
  219.     beq    sk0_sa        * jump if found
  220.     addq.w    #1,d6        * increment string length counter
  221.     bra    slen        * look at next byte
  222. sk0_sa:
  223.     move.l    (a2)+,a0    * get string address again
  224.     bsr    prefix        * print prefix spaces
  225. lp0_sa:
  226.     tst.b    (a0)        * end of string?
  227.     bne    sk1_sa        * no, keep going
  228.     bsr    postfix        * print postfix spaces
  229.     bra    loop        * continue parsing format string
  230. sk1_sa:
  231.     move.b    (a0)+,d0    * get char from string
  232.     move.w    d0,-(a7)    * push for output
  233.     bsr    putc        * output it
  234.     addq.l    #2,a7        * adjust stack
  235.     bra    lp0_sa        * continue
  236. *****************************************************************
  237. c_arg:
  238.     move.w    (a2)+,-(a7)    * get argument
  239.     bsr    putc        * send it out
  240.     addq.l    #2,a7        * adjust stack
  241.     bra    loop        * continue
  242. *****************************************************************
  243. v_arg:
  244.     move.l    (a2)+,-(a7)    * move both args at once
  245.     bsr    cursor        * perform function
  246.     addq.l    #4,a7        * adjust stack
  247.     bra    loop        * continue parse of control str
  248. *****************************************************************
  249. * DEFAULT: user has specified unknown control argument
  250. default:
  251.     move.w    d0,-(a7)    * we'll just print it.
  252.     bsr    putc        * so there it goes!
  253.     addq.l    #2,a7        * adjust stack
  254.     bra    loop        * that's all for here
  255. *****************************************************************
  256. * Case dispatch table for printf
  257. dispatch:
  258.     dc.w    9    * number of valid options
  259.      dc.b    0,'d'    * %d print signed decimal word 
  260.     dc.l    d_arg
  261.     dc.b    0,'u'    * %u print unsigned decimal word
  262.     dc.l    u_arg
  263.     dc.b    0,'D'    * %D print signed decimal longword
  264.     dc.l    D_arg
  265.     dc.b    0,'U'    * %U print unsigned decimal longword
  266.     dc.l    U_arg
  267.     dc.b    0,'x'    * %x print hex word
  268.     dc.l    x_arg
  269.     dc.b    0,'X'    * %X print hex longword
  270.     dc.l    X_arg
  271.     dc.b    0,'s'    * %s print null terminated string
  272.     dc.l    s_arg
  273.     dc.b    0,'c'    * %c print character
  274.     dc.l    c_arg
  275.     dc.b    0,'v'    * %v set cursor (X,Y)
  276.     dc.l    v_arg
  277.     dc.l    default    * all unknown cases handled here
  278.  
  279.     end
  280.